//! 配置服务实现

use async_trait::async_trait;
use nacos_core::{
    ConfigService, ConfigStorage, ConfigItem, EventListener, EventPublisher, Result, NacosError,
};
use std::sync::Arc;
use std::fmt;
use tracing::{debug, info, trace, warn, instrument};

/// 配置服务的实现
pub struct ConfigServiceImpl {
    config_storage: Arc<dyn ConfigStorage>,
    event_publisher: Arc<dyn EventPublisher>,
}

impl fmt::Debug for ConfigServiceImpl {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("ConfigServiceImpl")
         .field("config_storage", &"Arc<dyn ConfigStorage>")
         .field("event_publisher", &"Arc<dyn EventPublisher>")
         .finish()
    }
}

impl ConfigServiceImpl {
    pub fn new(
        config_storage: Arc<dyn ConfigStorage>,
        event_publisher: Arc<dyn EventPublisher>,
    ) -> Self {
        info!("Creating new ConfigServiceImpl");
        Self { config_storage, event_publisher }
    }

    fn calculate_md5(content: &str) -> String {
        format!("{:x}", md5::compute(content.as_bytes()))
    }
}

#[async_trait]
impl ConfigService for ConfigServiceImpl {
    #[instrument(skip(self), fields(namespace, group, data_id))]
    async fn get_config(&self, namespace: &str, group: &str, data_id: &str) -> Result<Option<String>> {
        trace!("Getting config");
        let config = self.config_storage.get_config(namespace, group, data_id).await?;
        Ok(config.map(|c| c.content))
    }

    #[instrument(skip(self, content), fields(namespace, group, data_id))]
    async fn publish_config(&self, namespace: &str, group: &str, data_id: &str, content: &str) -> Result<bool> {
        debug!("Publishing config");
        let new_config = match self.config_storage.get_config(namespace, group, data_id).await? {
            Some(mut old_config) => {
                debug!("Config already exists, updating version.");
                old_config.version += 1;
                old_config.content = content.to_string();
                old_config.md5 = Self::calculate_md5(content);
                old_config.update_time = chrono::Utc::now();
                old_config
            }
            None => {
                debug!("Config does not exist, creating new.");
                let mut config = ConfigItem::new(data_id.to_string(), group.to_string(), content.to_string());
                config.namespace = namespace.to_string();
                config.md5 = Self::calculate_md5(content);
                config
            }
        };
        self.config_storage.save_config(&new_config).await?;
        info!(version = new_config.version, "Successfully published config.");
        Ok(true)
    }

    #[instrument(skip(self), fields(namespace, group, data_id))]
    async fn remove_config(&self, namespace: &str, group: &str, data_id: &str) -> Result<bool> {
        info!("Removing config");
        self.config_storage.delete_config(namespace, group, data_id).await?;
        Ok(true)
    }

    #[instrument(skip(self), fields(namespace, group, data_id))]
    async fn get_config_detail(&self, namespace: &str, group: &str, data_id: &str) -> Result<Option<ConfigItem>> {
        trace!("Getting config detail");
        self.config_storage.get_config(namespace, group, data_id).await
    }

    #[instrument(skip(self), fields(namespace, group))]
    async fn list_configs(&self, namespace: &str, group: Option<&str>) -> Result<Vec<ConfigItem>> {
        trace!("Listing configs");
        self.config_storage.list_configs(namespace, group).await
    }

    #[instrument(skip(self, listener), fields(namespace, group, data_id))]
    async fn add_listener(&self, _namespace: &str, _group: &str, _data_id: &str, listener: Box<dyn EventListener>) -> Result<()> {
        warn!(listener_name = listener.name(), "add_listener is not fully implemented yet.");
        Err(NacosError::Unknown("Not implemented".to_string()))
    }

    #[instrument(skip(self), fields(namespace, group, data_id, listener_name))]
    async fn remove_listener(&self, _namespace: &str, _group: &str, _data_id: &str, _listener_name: &str) -> Result<()> {
        warn!("remove_listener is not fully implemented yet.");
        Err(NacosError::Unknown("Not implemented".to_string()))
    }

    #[instrument(skip(self), fields(namespace, group, data_id))]
    async fn get_config_md5(&self, namespace: &str, group: &str, data_id: &str) -> Result<Option<String>> {
        trace!("Getting config MD5");
        let config = self.config_storage.get_config(namespace, group, data_id).await?;
        Ok(config.map(|c| c.md5))
    }
}

impl ConfigServiceImpl {
    /// 启动配置服务
    ///
    /// # 返回值
    /// - `Ok(())`: 服务启动成功
    /// - `Err(NacosError)`: 启动失败时的错误
    ///
    /// # 行为
    /// 初始化配置服务，验证存储连接。
    pub async fn start(&self) -> Result<()> {
        info!("Starting config service");
        
        // 验证存储连接
        let test_configs = self.config_storage.list_configs("public", None).await?;
        info!("Config storage initialized with {} configs", test_configs.len());
        
        info!("Config service started successfully");
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use nacos_core::Event;
    use nacos_storage::{memory::MemoryConfigStorage, file::FileConfigStorage, file::FileStorage};
    use tempfile::tempdir;

    // --- Mock Event Publisher ---
    #[derive(Debug)]
    struct MockEventPublisher;

    #[async_trait]
    impl EventPublisher for MockEventPublisher {
        async fn publish(&self, _event: Event) -> Result<()> { Ok(()) } 
        async fn subscribe(&self, _listener: Box<dyn EventListener>) -> Result<()> { Ok(()) }
        async fn unsubscribe(&self, _listener_name: &str) -> Result<()> { Ok(()) }
    }

    // --- Reusable Test Suite ---
    async fn run_config_service_test_suite(service: impl ConfigService) {
        let (n, g, d, c) = ("public", "test_group", "test_data_id", "test_content");

        // 1. Publish a new config
        assert!(service.publish_config(n, g, d, c).await.unwrap());

        // 2. Get the config and verify content
        let retrieved_content = service.get_config(n, g, d).await.unwrap().unwrap();
        assert_eq!(retrieved_content, c);

        // 3. Get config detail and verify
        let detail = service.get_config_detail(n, g, d).await.unwrap().unwrap();
        assert_eq!(detail.content, c);
        assert_eq!(detail.version, 1);

        // 4. Publish an update
        let new_c = "new_content";
        assert!(service.publish_config(n, g, d, new_c).await.unwrap());
        let updated_detail = service.get_config_detail(n, g, d).await.unwrap().unwrap();
        assert_eq!(updated_detail.content, new_c);
        assert_eq!(updated_detail.version, 2);

        // 5. List configs
        let list = service.list_configs(n, Some(g)).await.unwrap();
        assert_eq!(list.len(), 1);
        assert_eq!(list[0].data_id, d);

        // 6. Remove the config
        assert!(service.remove_config(n, g, d).await.unwrap());
        assert!(service.get_config(n, g, d).await.unwrap().is_none());
    }

    // --- Integration Tests ---

    #[tokio::test]
    async fn test_config_service_with_memory_storage() {
        let storage = Arc::new(MemoryConfigStorage::new());
        let publisher = Arc::new(MockEventPublisher);
        let service = ConfigServiceImpl::new(storage, publisher);
        
        run_config_service_test_suite(service).await;
    }

    #[tokio::test]
    async fn test_config_service_with_file_storage() {
        let dir = tempdir().unwrap();
        let file_storage = Arc::new(FileStorage::new(dir.path()).await.unwrap());
        let storage = Arc::new(FileConfigStorage::new(file_storage));
        let publisher = Arc::new(MockEventPublisher);
        let service = ConfigServiceImpl::new(storage, publisher);

        run_config_service_test_suite(service).await;
    }
}
